package be.rivendale.geometry;

import static be.rivendale.mathematics.MathematicalAssert.*;
import be.rivendale.mathematics.Ray;
import be.rivendale.mathematics.Rectangle;
import be.rivendale.mathematics.Triple;
import org.junit.Test;

public class CameraTest {
    @Test
    public void constructorSetsFocusPointCorrectly() throws Exception {
        assertPointEquals(new Triple(0, 0, -5), new Camera().getFocusPoint());
    }

    @Test
    public void constructorSetsViewPortCorrectly() throws Exception {
        assertRectangleEquals(new Rectangle(new Triple(-4, 3, 0),
                new Triple(-4, -3, 0),
                new Triple(4, 3, 0)
        ), new Camera().getViewPlane());
    }

    @Test
    public void castRayReturnsRayThroughTopLeftCornerWhenBothSampleIndicesAreZero() throws Exception {
        Camera camera = new Camera();
        Ray ray = camera.castRay(0, 0, 10, 10);
        assertRayEquals(new Ray(camera.getFocusPoint(), camera.getTopLeftCorner()), ray);
    }

    @Test
    public void castRayReturnsRayThroughTopRightCornerWhenTheHorizontalSampleIndexIsAtMaximumAndTheVerticalSampleIndexIsZero() throws Exception {
        Camera camera = new Camera();
        Ray ray = camera.castRay(9, 0, 10, 10);
        assertRayEquals(new Ray(camera.getFocusPoint(), camera.getTopRightCorner()), ray);

    }

    @Test
    public void castRayReturnsRayThroughBottomLeftCornerWhenTheVerticalSampleIndexIsAtMaximumAndTheHorizontalSampleIndexIsZero() throws Exception {
        Camera camera = new Camera();
        Ray ray = camera.castRay(0, 9, 10, 10);
        assertRayEquals(new Ray(camera.getFocusPoint(), camera.getBottomLeftCorner()), ray);
    }

    @Test
    public void castRayReturnsRayThroughBottomRightCornerWhenBothSampleIndicesAreAtMaximum() throws Exception {
        Camera camera = new Camera();
        Ray ray = camera.castRay(9, 9, 10, 10);
        assertRayEquals(new Ray(camera.getFocusPoint(), camera.getBottomRightCorner()), ray);
    }

    @Test
    public void getTopLeftCornerReturnsTopPointAOfViewPort() throws Exception {
        Camera camera = new Camera();
        assertPointEquals(camera.getViewPlane().getA(), camera.getTopLeftCorner());
    }

    @Test
    public void getTopRightCornerReturnsPointCOfViewPort() throws Exception {
        Camera camera = new Camera();
        assertPointEquals(camera.getViewPlane().getC(), camera.getTopRightCorner());
    }

    @Test
    public void getBottomLeftCornerReturnsPointBOfViewPort() throws Exception {
        Camera camera = new Camera();
        assertPointEquals(camera.getViewPlane().getB(), camera.getBottomLeftCorner());
    }

    @Test
    public void getBottomRightCornerReturnsPointDOfViewPort() throws Exception {
        Camera camera = new Camera();
        assertPointEquals(camera.getViewPlane().getD(), camera.getBottomRightCorner());
    }

    @Test(expected = IllegalArgumentException.class)
    public void castRayThrowsIllegalArgumentExceptionWhenXIsNegative() {
        new Camera().castRay(-1, 10, 20, 20);
    }

    @Test(expected = IllegalArgumentException.class)
    public void castRayThrowsIllegalArgumentExceptionWhenYIsNegative() {
        new Camera().castRay(10, -1, 20, 20);
    }

    @Test(expected = IllegalArgumentException.class)
    public void castRayThrowsIllegalArgumentExceptionWhenXIsGreaterThenWith() {
        new Camera().castRay(21, 10, 20, 20);
    }

    @Test(expected = IllegalArgumentException.class)
    public void castRayThrowsIllegalArgumentExceptionWhenXEqualToWith() {
        new Camera().castRay(20, 10, 20, 20);
    }

    @Test(expected = IllegalArgumentException.class)
    public void castRayThrowsIllegalArgumentExceptionWhenYIsGreaterThenHeight() {
        new Camera().castRay(10, 21, 20, 20);
    }

    @Test(expected = IllegalArgumentException.class)
    public void castRayThrowsIllegalArgumentExceptionWhenYEqualToHeight() {
        new Camera().castRay(10, 20, 20, 20);
    }

    @Test(expected = IllegalArgumentException.class)
    public void castRayThrowsIllegalArgumentExceptionWhenWidthIsLessThenTwo() {
        new Camera().castRay(0, 0, 1, 2);
    }

    @Test(expected = IllegalArgumentException.class)
    public void castRayThrowsIllegalArgumentExceptionWhenHeightIsLessThenTwo() {
        new Camera().castRay(0, 0, 2, 1);
    }

	@Test
	public void horizontalViewAngleReturnsCorrectAngleOfView() throws Exception {
		assertRealEquals(1.349482, new Camera().horizontalViewAngle());
	}

	@Test
	public void verticalViewAngleReturnsCorrectAngleOfView() throws Exception {
		assertRealEquals(1.080839, new Camera().verticalViewAngle());
	}

	@Test
	public void diagonalViewAngleReturnsCorrectAngleOfView() throws Exception {
		assertRealEquals(1.570796, new Camera().diagonalViewAngle());
	}

	@Test
	public void focalLengthReturnsDistanceFromFocusPointToCenterOfViewPlane() throws Exception {
		assertRealEquals(5, new Camera().focalLength());
	}

	@Test
	public void horizontalViewPlaneSizeCalculatesTheHorizontalSizeOfTheFilm() throws Exception {
		assertRealEquals(8, new Camera().horizontalViewPlaneSize());
	}

	@Test
	public void verticalViewPlaneSizeCalculatesTheVerticalSizeOfTheFilm() throws Exception {
		assertRealEquals(6, new Camera().verticalViewPlaneSize());
	}

	@Test
	public void diagonalViewPlaneSizeCalculatesTheDiagonalSizeOfTheFilm() throws Exception {
		assertRealEquals(10, new Camera().diagonalViewPlaneSize());
	}
}
